#!/usr/bin/env ruby

require 'ls_remote_zip'
require 'net/http'
require 'zip/zip'
require 'fileutils'
require 'grok'
require 'network'
include FileUtils

LINKS = "links.txt"
CDIR = 'cdir'
ZIPS = 'zips'
SYSTEMS = 'systems'

urls = IO.readlines("links.txt").map { |x| x.chomp }.select { |x| !x.empty? && !(x =~ /\s*#.*/) }
files = urls.map { |url| CDIR + "/" + File.basename(url).ext("cdir") }


###########################################################################
###########################################################################
###########################################################################

# The Array power set is stolen from http://snippets.dzone.com/posts/show/3524  
class Array  
  # Returns the "power set" for this Array. This means that an array with all  
  # subsets of the array's elements will be returned.  
  def power_set  
    # the power set line is stolen from http://johncarrino.net/blog/2006/08/11/powerset-in-ruby/  
    inject([[]]){|c,y|r=[];c.each{|i|r<<i;r<<i+[y]};r}  
  end  
end  

###########################################################################
###########################################################################
###########################################################################

desc "Get the list of files inside each zip file"
task :getcdirs => files

desc "Download the zip files"
task :getzips => files.map { |x| ZIPS + "/" + File.basename(x).ext("zip") }

desc "Unpack the zip files"
task :unpack => files.map { |x| "#{SYSTEMS}/#{File.basename(x).ext}" }

directory CDIR
directory ZIPS
directory SYSTEMS

files.each do |name|
  basename = File.basename(name).ext

  file "#{SYSTEMS}/#{basename}/duplicates.txt" do
    chdir "#{SYSTEMS}/#{basename}"
    system "Extract.rake duplicates"
    chdir "../.."
  end

  file name => CDIR do
    uri = urls.find { |s| s.include? File.basename(name).ext("zip") }
    puts "Getting cdir from #{uri}"
    cdir = cdir_from_uri(uri)
    File.open(name, "w") { |f| f.write(cdir) }
  end

  zipname = "#{ZIPS}/#{basename}.zip"
  file zipname => ZIPS do
    puts zipname
    if !File.exist? zipname
      url = urls.find { |s| s.include?(basename) }
      system "wget #{url} --output-document=#{zipname}"
      touch zipname
    end
  end

  file "#{SYSTEMS}/#{basename}" => zipname do |t|
    puts "bli"
    mkdir_p "#{SYSTEMS}/#{basename}/jars"
    system "unzip -j -d #{t.name}/jars #{zipname} \\*.jar"
  end
end

desc "Compute metrics from names.mod"
task :modmetrics do # TODO: dependencies
  File.open("mod-metrics.csv", "w") do |f|
    f.puts "system,classes,modules,artificial"
    Dir.glob("#{SYSTEMS}/*").select{ |x| File.directory?(x) }.each do |system|
      sysname = File.basename(system)
      puts system
      pairs = read_pairs("#{system}/names.mod")
      modules = pairs.map { |_,m| m }.uniq.count
      classes = pairs.size
      f.puts "#{sysname},#{classes},#{modules},N"
      arch = Network.new
      arch.load2 "#{system}/arch-names"
      isolated = arch.nodes.select { |n| n.degree == 0 }.map { |n| n.eid }
      #if isolated.size <= 4
        isolated.power_set.each do |set|
          next if set.empty?
          p set
          classes = pairs.select { |c, m| !set.include?(m) }.size
          name = set.inspect.gsub(/[,"]/, "")
          f.puts "#{sysname} - #{name},#{classes},#{modules - set.size},Y"
        end
      #end
    end
  end
end

#file 'cdir/metrics.csv' => files do |t|
desc "Compute metrics from the cdir files"
task :cdirmetrics do
  File.open("cdir/metrics.csv", "w") do |fm|
    fm.puts("filename,jarfiles,kbytes,classes")
    files.each do |file|
      puts "Processing file #{file}"
      File.open(file, 'r') do |cdir|
        entries = entries_from_cdir(cdir).select {|k,v| k =~ /\.jar$/}.map { |a, b| b }
        kbytes = entries.inject(0) { |sum, e| sum + e.size } / 1000
        nclasses = (524.6 + 0.459*kbytes).to_i
        fm.puts "#{File.basename(file).ext},#{entries.size},#{kbytes},#{nclasses}"
      end
    end
  end
end

#desc "Compute metrics from the jar files"
#task :jarmetrics do
#  File.open("jar-metrics.csv", "w") do |f|
#    f.puts "system,classes,modules"
#    puts "system,classes,modules"
#    Dir.glob("#{SYSTEMS}/*").select{ |x| File.directory?(x) }.each do |system|
#      system = File.basename(system)
#      nclasses = 0
#      nmods = 0
#      #puts ("#{SYSTEMS}/#{system}/**/*.jar")
#      Dir.glob("#{SYSTEMS}/#{system}/**/*.jar") do |jar|
#        puts jar
#        begin
#          Zip::ZipFile.foreach(jar) { |entry| nclasses += 1 if entry.to_s =~ /\.class$/ }
#        rescue
#          puts "ERRRRRRROOOOOOOOOOO"
#        end
#        nmods += 1
#      end
#      f.puts "#{system},#{nclasses},#{nmods}"
#      puts "#{system},#{nclasses},#{nmods}"
#    end
#  end
#end
